import shutil
import os
import re

#number of trials per planner/problem combination
numTrials = 10
plannerIters = {'discrete':2000,'normal':10000,'lazy':50000}

"""
#problem specific items
problemFile = 'problems/circlestack.strips'
modProblem = 'problems/circlestack_batch5.strips'
problemParams = ["numCircles","planner","heuristicWeighting","heuristicTechnique"]

domains = {'numCircles':[10,15,20,25,30,35,40,45,50],
           'planner':['normal','lazy','discrete'],
           'heuristicWeighting':[1,5,50],
           'heuristicTechnique':['goal','discrete']}
"""

problemFile = 'problems/blocks2d.strips'
modProblem = 'problems/blocks2d_batch.strips'
problemParams = ["numBlocks","planner","heuristicWeighting","heuristicTechnique"]

domains = {'numBlocks':[3,4,5,6,7,8,9,10],
           'planner':['normal','lazy','discrete'],
           'heuristicWeighting':[1,5,50],
           'heuristicTechnique':['goal','discrete']}

ignoreList = [{'planner':'discrete','heuristicTechnique':'discrete'},
              {'planner':'discrete','heuristicWeighting':5},
              {'planner':'discrete','heuristicWeighting':50},

              {'planner':'discrete'},
              {'planner':'lazy'},
              {'heuristicWeighting':'goal'},
              {'heuristicWeighting':1},
              {'heuristicWeighting':50},
              ]

valREs = [(v,re.compile("(\s*"+v+"\s*=\s*)(\S+)(\s*)")) for v in domains]

def modifyProblem(origfn,setting,newfn):
    f = open(origfn,'r')
    fnew = open(newfn,'w')
    REmatched = dict((v,False) for (v,exp) in valREs)
    for line in f.readlines():
        matched = False
        for (v,expr) in valREs:
            found = expr.match(line)
            if found:
                fnew.write(found.group(1)+repr(setting[v])+'\n')
                matched = True
                if REmatched[v]:
                    raise RuntimeError('Matched '+v+' multiple times?')
                REmatched[v] = True
                break
        if not matched:
            fnew.write(line)
    missing = [v for (v,m) in REmatched.iteritems() if not m]
    if len(missing) > 0:
        raise RuntimeError("Didn't match "+", ".join(missing)+"?")
            
def ignoreSetting(setting):
    for cond in ignoreList:
        match = True
        for (k,v) in cond.iteritems():
            if setting[k] != v:
                match = False
        if match:
            return True
    return False

def solved(fn):
    f = open(fn,'r')
    lines = f.readlines()
    f.close()
    if lines[-1].find('Solved') >= 0:
        return True
    return False

#do it
#enumerate all combinations
#all planners are tested
#problems are tested in increasing difficulty until they are all completed
plannervals = ['planner','heuristicWeighting','heuristicTechnique']
#problemvals = []
problemvals = ['numBlocks']
#problemvals = ['numCircles']
plannerdomains = []
problemdomains = []
for (k,vals) in sorted(domains.iteritems()):
    if k in plannervals:
        if len(plannerdomains)==0:
            plannerdomains = [(v,) for v in vals]
        else:
            plannerdomains = [d+(v,) for d in plannerdomains for v in vals]
    else:
        if len(problemdomains)==0:
            problemdomains = [(v,) for v in vals]
        else:
            problemdomains = [d+(v,) for d in plannerdomains for v in vals]

def test(setting):
    iters = plannerIters[setting['planner']]
        
    print "Planning with settings",setting
    #do the work
    modifyProblem(problemFile,setting,modProblem)
    numSolved = 0
    for trial in xrange(numTrials):
        os.system('./pytamp.py --iters %d --redirect %s > output.txt'%(iters,modProblem))
        #detect a success
        if solved('output.txt'):
            numSolved += 1
    print 'Solved %d/%d trials'%(numSolved,numTrials)
    return numSolved

for planner in plannerdomains:
    plannerdict = dict(zip(sorted(plannervals),planner))
    if len(problemdomains)==0:
        if ignoreSetting(plannerdict): continue
        numSolved = test(plannerdict)
        if numSolved == 0:
            #all trials failed for this problem, break to the next guy
            break
    for problem in problemdomains:
        problemdict = dict(zip(sorted(problemvals),problem))
        setting = plannerdict.copy()
        setting.update(problemdict)

        if ignoreSetting(setting): continue
        numSolved = test(setting)
        if numSolved <= numTrials/2:
            #half of trials failed for this problem, break to the next guy
            break


